const request = require('request');
const config = require("../db/config");
const httpUtils = require("../utils/httpUtils");
const constants = require("../db/constants");
const mediaServerModel = require("../model/mediaServer");
const log4js     = require('../utils/logUtils');
const logger     = log4js.getLogger('service');
const stringUtils = require("../utils/stringUtils");
const settingModel = require("../model/setting");

const TAG = "[调用ZlMediaKitRestful接口]";
const ZlMediaKit = {
    // 记录已使用的端口号
    ports:{},
    async playBack(app, stream, path, targetIp, targetPort, localUdpPort, establish, connected) {
        const that = this;
        this.pullFfmpeg(app,stream, path).then(() => {
            setTimeout(function () {
                that.push(app, stream, targetIp, targetPort, localUdpPort, establish, connected)
            }, 2000);
        }).catch((e) => {
            logger.error(TAG, "请求流媒体接口返回异常", e);
        });
    },
    async play(app, stream, url, targetIp, targetPort, localUdpPort, establish, connected) {
        const that = this;
        try {
            await this.pull(app , stream, url.replace('{channel}', '1'));
            setTimeout(function () {
                that.push(app, stream, targetIp, targetPort, localUdpPort, establish, connected)
            }, 1000);
        } catch (e) {
            logger.error(TAG, "请求流媒体接口返回异常", e);
        }
    },
    // toUri 作为stream值
    async stop(key) {
        try {
            await this.stopPush(key);
        } catch (e) {
            logger.error(e);
        }
        try {
            await this.stopPull(key);
        } catch (e) {
            logger.error(e);
        }
    },
    async stopPull(key) {
        // TODO: 改从数据库获取
        return new Promise(function (resolve, reject) {
            const proxy = config.ZLK.url + 'index/api/delStreamProxy?key=' + key + "&secret=" + config.ZLK.secret;
            const options = {
                url: proxy
            };
            logger.info(TAG, "调用删除拉流代理接口 参数", options);
            request.get(options, function (err, response, ret) {
                if (err) {
                    reject(err);
                } else {
                    resolve(JSON.parse(ret).data);
                }
            });
        });

    },
    async stopPush(stream) {
        const proxy = config.ZLK.url + 'index/api/stopSendRtp?vhost=__defaultVhost__&app=live&stream=' + stream + "&secret=" + config.ZLK.secret;
        let options = {
            url: proxy
        };
        logger.info(TAG, "请求 ZlMediaKit 停止推流 参数", options);
        return new Promise(function (resolve, reject) {
            request.get(options, function (err, response, ret) {
                logger.trace(TAG, '停止推流接口请求错误', err, ret);
                if (err) {
                    reject(ret);
                } else {
                    resolve(ret);
                }
            });
        });

    },

    /**
     * 添加拉流代理
     * @param app 应用名称
     * @param stream
     * @param url
     * @return {Promise<unknown>}
     */
    async pull(app, stream, url) {
        return new Promise(function (resolve, reject) {
            const proxy = config.ZLK.url + 'index/api/addStreamProxy?vhost=__defaultVhost__&app=' + app + '&stream=' + stream + '&url=' + encodeURIComponent(url) + "&secret=" + config.ZLK.secret
                +"&enable_mp4=1&rtp_type=tcp";
            let options = {
                url: proxy
            };
            request.get(options, function (err, response, ret) {
                if (err) {
                    logger.error("请求接口返回异常", err, "参数", options);
                } else {
                    try {
                        let body = JSON.parse(ret);
                        if (body.code === 0) {
                            logger.info(TAG, "添加拉流代理成功", stream, body.data.key);
                            resolve(false);
                        } else if (body.msg.indexOf('already exists') > -1) {
                            logger.info(TAG, "拉流代理已经存在", stream, '返回', body, url);
                            resolve('拉流代理已经存在');
                        } else {
                            logger.error(TAG, "推流接口返回异常", body.msg, url);
                            reject('code 不等于 0');
                        }
                    } catch (e) {
                        logger.error(TAG, e, ret);
                    }
                }
            });
        });
    },

    /**
     * 点播本地文件
     * @param app
     * @param stream
     * @param path
     * @return {Promise<unknown>}
     */
    async pullZlkFfmpeg(app, stream, path) {
        const mediaServer = await mediaServerModel.getDefault();
        const dst_url = `rtmp://${mediaServer.media_ip}:${mediaServer.rtmp_port}/${app}/${stream}` ;
        return new Promise(function (resolve, reject) {
            const proxy = config.ZLK.url + 'index/api/addFFmpegSource?src_url=' + encodeURIComponent(path) + "&secret=" + config.ZLK.secret + "&enable_mp4=0&timeout_ms=10000&dst_url=" + encodeURIComponent(dst_url);
            let options = {
                url: proxy
            };
            logger.info(TAG, "请求 ZlMediaKit 拉流代理 参数", options);
            request.get(options, function (err, response, ret) {
                if (err) {
                    logger.error("请求接口返回异常", err, "参数", options);
                } else {
                    try {
                        let body = JSON.parse(ret);
                        if (body.code === 0) {
                            logger.info(TAG, "添加拉流代理成功", stream, body.data.key);
                            resolve(false);
                        } else if (body.msg.indexOf('already exists') > -1) {
                            logger.info(TAG, "拉流代理已经存在", stream, '返回', body, path);
                            resolve('拉流代理已经存在');
                        } else {
                            logger.error(TAG, "推流接口返回异常", body.msg, path);
                            reject('code 不等于 0');
                        }
                    } catch (e) {
                        logger.error(TAG, e, ret);
                    }
                }
            });
        });
    },
    // 创建 ffmpeg 拉流代理
    async pullFfmpeg(app, stream, path) {
        logger.info(TAG, "添加 ffmpeg 拉流代理, stream=", stream, 'path=', path);
        return new Promise(function (resolve) {
            // 直接调用 命令行推流 ffmpeg.exe -re -i E:/record/recordings/2024/01/02/preview/20240102-134325.mkv -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv rtmp://127.0.0.1/live/41010500002000000001_41010500002000000005_1704170931_1704174530
            // 定义命令行字符串，然后使用nodejs执行命令行
            const command = 'ffmpeg -re -i ' + path + ' -vcodec copy -acodec copy -f rtsp rtmp://127.0.0.1:1935/' + app + '/' + stream;
            logger.info(TAG, "ffmpeg拉流命令行", command);
            const exec = require('child_process').exec;
            const child = exec(command, function (err, stdout, stderr) {
                if (err) {
                    logger.error(TAG, "ffmpeg拉流命令行返回异常", err);
                } else {
                    // logger.info(TAG, "ffmpeg拉流命令行返回", stdout, stderr);
                }
            });
            resolve(child);

        });
    },
    /**
     * 推流
     * @param app
     * @param stream
     * @param targetIp
     * @param targetPort
     * @param localUdpPort
     * @param establish
     * @param connected
     * @return {Promise<unknown>}
     */
    push(app, stream, targetIp, targetPort, localUdpPort, establish, connected) {
        establish();
        const proxy = config.ZLK.url +
            `index/api/startSendRtp?vhost=__defaultVhost__&app=${app}&stream=${stream}&ssrc=1&dst_url=`
            + targetIp + '&dst_port='
            + targetPort + '&is_udp=1&src_port=' + localUdpPort + "&secret=" + config.ZLK.secret;
        let options = {
            url: proxy
        };
        logger.info(TAG, "请求流媒体sendRtp接口参数", options);
        return new Promise(function (resolve, reject) {
            request.get(options, function (err, response, ret) {
                logger.info(TAG, "请求sendRtp接口返回", err, ret);
                if (err) {
                    reject(err);
                } else {
                    connected(stream);
                }
            });
        });
    },
    // 读取目标媒体服务器配置信息
    getServerConfig(host, port, secret) {
        if(!secret) secret = '';
        if(secret==='undefined') secret = '';
        let param="";
        if(secret){
            param = "secret=" + secret;
        }
        let url = `http://${host}:${port}/index/api/getServerConfig?${param}`;
        return new Promise(function (resolve, reject) {
            httpUtils.get(url, '').then(tmp => {
                if (tmp.code === 0) {
                    tmp.code = constants.httpCode.OK.code
                    tmp.message = constants.httpCode.OK.message
                } else {
                    tmp.code = constants.httpCode.ILLEGAL_TOKEN.code;
                    tmp.message = constants.httpCode.ILLEGAL_TOKEN.message
                }
                resolve(tmp);
            }).catch(e => {
                reject(e);
            });
        });
    },
    /**
     * 调用zlmediaKit的 /index/api/listRtpServer 用来查询状态
     * @param mediaServer
     * @return {Promise<unknown>}
     */
    async queryStatus(mediaServer) {
        const url = this.getUrl(mediaServer, '/index/api/listRtpServer');
        let param = "?secret=" + mediaServer.secret;
        return new Promise(function (resolve, reject) {
            httpUtils.get(url, param).then((res) => {
                resolve(res);
            }).catch((e) => {
                logger.error(TAG, e);
                reject(e);
            });
        });
    },
    getUrl(mediaServer, path){
        const host = `http://${mediaServer.intranet}:${mediaServer.http_port}/`;
        return host + stringUtils.removePrefix(path);
    },
    /**
     * 调用zlmediaKit的 /index/api/listRtpServer
     **/
    async listRtpServer(serverId) {
        let host = await mediaServerModel.getInfoByServerId(serverId);

        if (host && host.zlk_api_host) {
            let url = host.zlk_api_host + 'index/api/listRtpServer';
            let param = "?secret=" + host.secret;
            return httpUtils.get(url, param);
        } else {
            logger.error(TAG, "请打开网页设置媒体服务器地址。");
        }
    },
    /**
     * 调用zlmediaKit的 /index/api/openRtpServer接口 ，用于打开一个rtp端口
     */
    async openRtpServer(req){
        const that = this;
        const serverId = req.body.mediaServerId;
        const streamId = req.body.stream_id;

        let host = await mediaServerModel.getInfoByServerId(serverId);
        let url = host.zlk_api_host + 'index/api/openRtpServer';
        // 选取一个空余端口号
        let max = host.rtp_max_port;
        let min = host.rtp_min_port;
        if(!that.ports.index) that.ports.index = min-2;

        let port;
        if (that.ports[streamId]) {
            port = that.ports[streamId];
        } else {
            that.ports.index += 2;
            port = that.ports.index;
            that.ports[streamId] = port;
        }
        if (port > max) {
            logger.error(TAG,`openRtpServer时,没有可用端口了 streamId=${streamId}`);
        } else {
            let param = `secret=${host.secret}&port=0&enable_tcp=1&stream_id=${streamId}`;

            try {
                let res = await httpUtils.get(url, param);
                return {res: res, intranet: host.intranet, media_ip: host.media_ip};
            }catch (e){
                 logger.error(TAG,`mediaServerId=${serverId} stream_id=${streamId} 请求媒体服务器 openRtsServer 出错, error=${e}`);
            }
        }
    },
    /**
     * 调用zlmediaKit的 /index/api/closeRtpServer
     **/
    async closeRtpServer(serverId, stream) {
        let host = await mediaServerModel.getInfoByServerId(serverId);
        let url = host.zlk_api_host + 'index/api/closeRtpServer';
        let param = "?secret=" + host.secret + "&port=0&enable_tcp=false&stream_id=" + stream;
        logger.info(TAG, 'get host info', host, 'serverId', serverId, 'param=', param);
        httpUtils.get(url, param).then((res) => {
            logger.log(TAG, res);
        }).catch((e) => {
            logger.error(TAG, e);
        });
    },
    /**
     * 释放所有rtp资源
     */
    resetRtpServer(serverId) {
        this.listRtpServer(serverId).then(async (list) => {
            logger.info(TAG, 'rtp server 列表', list);
            for (let i in list.data) {
                let stream = list.data[i].stream_id;
                await this.closeRtpServer(serverId, stream);
            }
        }).catch((err) => {
            logger.error(TAG, '释放rtp资源出错,检查媒体服务器是否正常。错误信息=', err);
        });
    },
    async startRecord(serverId, type, vhost, app, stream, customized_path, max_second){
        const host = await mediaServerModel.getInfoById(serverId);
        let param = `?secret=${host.secret}&type=${type}&vhost=${vhost}&app=${app}&stream=${stream}&customized_path=${customized_path}&max_second=${max_second}`;
        const url = host.zlk_api_host + 'index/api/startRecord' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    },
    async stopRecord(serverId, type, vhost, app, stream){
        const host = await mediaServerModel.getInfoById(serverId);
        let param = `?secret=${host.secret}&type=${type}&vhost=${vhost}&app=${app}&stream=${stream}`;
        const url = host.zlk_api_host + 'index/api/stopRecord' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    },
    // 查询录制状态
    async isRecording(serverId, type, vhost, app, stream){
        const host = await mediaServerModel.getInfoById(serverId);
        let param = `?secret=${host.secret}&type=${type}&vhost=${vhost}&app=${app}&stream=${stream}`;
        const url = host.zlk_api_host + 'index/api/isRecording' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    },
    // 查询录制文件列表
    async listRecordFiles(hostModel, type, vhost, app, stream, customized_path, period){
        let param = `?secret=${hostModel.secret}&type=${type}&vhost=${vhost}&app=${app}&stream=${stream}&customized_path=${customized_path}&period=${period}`;
        const url = hostModel.zlk_api_host + 'index/api/getMp4RecordFile' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    },
    // 获取流列表
    async listStreams(serverId){
        const host = await mediaServerModel.getInfoById(serverId);
        return await this.listStreamsByMediaServer(host);
    },
    // 获取流列表
    async listStreamsByMediaServer(mediaServer){
        const vhost = '__defaultVhost__';

        let param = `?secret=${mediaServer.secret}&schema=rtmp&vhost=${vhost}&app=&stream=`;
        const url = mediaServer.zlk_api_host + 'index/api/getMediaList' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    },
    // 获取截图
    async snap (serverId, mrl, timeout_sec, expire_sec){
        const host = await mediaServerModel.getInfoById(serverId);

        let param = `?secret=${host.secret}&url=${mrl}&timeout_sec=${timeout_sec}&expire_sec=${expire_sec}`;
        const url = host.zlk_api_host + 'index/api/getSnap' + param;
        try {
            return await httpUtils.get(url, param);
        }catch (e) {
            return {code: 1, msg: e};
        }
    }
};
module.exports = ZlMediaKit;
